<?php

namespace App\Model;

use App\Services\AdapayService;
use App\Services\AliPayService;
use App\Services\WechatService;
use Carbon\Carbon;
use Hyperf\Database\Model\Relations\BelongsTo;
use Hyperf\Utils\Arr;
use Util\Common;

/**
 * App\PaymentOrder
 *
 * @property int $id
 * @property int $user_id 用户
 * @property int $device_id 用户
 * @property int $fee 金额
 * @property \App\Model\User $user 用户模型
 * @property int $give_fee 退款金额
 * @property string $number 订单号
 * @property string $type 类型
 * @property \Carbon\Carbon|null $paid_at 支付时间
 * @property string $payment_type 支付方式
 * @property array|null $extra 其他信息
 */
class BalanceOrder extends Model
{
    public bool $timestamps = true;
    protected ?string $table = 'balance_orders';


    const STATUS_UNPAID = 'unpaid';
    const STATUS_PAID = 'paid';
    const STATUS_FAILED = 'failed';
    const STATUS_REFUNDED = 'refunded';

    const USER_SOURCE_TO_PAYMENT_TYPE = [
        User::SOURCE_ALI_PAY => Bill::PAYMENT_TYPE_ALI_PAY,
        User::SOURCE_WE_CHAT => Bill::PAYMENT_TYPE_WE_CHAT_PAY,
    ];


    protected array $fillable = [
        'type', 'number', 'payment_type',
        'extra', 'status', 'out_ord_id', 'user_id',
        'fee', 'paid_at', 'give_fee', 'payment_id', 'device_id', 'return_fee'
    ];

    protected array $casts = [

    ];

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id', 'id');
    }

    /**充值余额支付后逻辑
     * @param array $params
     * @return void
     */
    public function balanceNotify(array $params)
    {
        if ($params['status'] == 'succeeded') {
            $this->status = self::STATUS_PAID;
            $this->paid_at = $params['end_time'];
            $this->payment_id = $params['id'];
            $this->out_ord_id = $params['out_trans_id'];
            $this->save();
            $this->user->balance += $this->fee;
            $this->user->save();
            $couponCache = "coupon_cache_key" . $this->id;
            if ($this->device_id) {
                if (redis()->exists($couponCache)) {
                    return 'succeeded';
                }
                $device = Device::where('id', $this->device_id)->first();
                if ($device->child_distributor_id > 0) {
                    $distributorId = $device->child_distributor_id;
                } else {
                    $distributorId = $device->distributor_id;
                }
                $today = date('Y-m-d', time());
                $coupon = Coupon::where('distributor_id', $distributorId)
                    ->where('type', Coupon::TYPE_MAP[Coupon::TYPE_RECHARGE_RECEIVE])
                    ->where('start_date', '<=', $today)
                    ->where('end_date', '>=', $today)
                    ->where('is_active', 1)
                    ->orderBy('id', 'desc')
                    ->first();
                $number = 0;
                if ($coupon) {
                    $cacheKey = Coupon::COUPON_MONEY_CACHE . $coupon->id;
                    $receiveData = redis()->hGetAll($cacheKey);
                    $cacheDevice = Coupon::COUPON_DEVICE_CACHE . $coupon->id;
                    $devices = redis()->sMembers($cacheDevice);
                    if (!in_array($this->device_id, $devices)) {
                        redis()->setex($couponCache, 60 * 10, 1);
                        return '';
                    }
                    if ($receiveData) {
                        krsort($receiveData);
                        foreach ($receiveData as $k => $v) {
                            if ($this->fee >= $k) {
                                $number = (int)$v;
                                break;
                            }
                        }
                    }
                    $insertRecord = [];
                    try {
                        for ($i = 0; $i < $number; $i++) {
                            $insertRecord[] = [
                                'coupon_id' => $coupon->id,
                                'user_id' => $this->user_id,
                                'expires_at' => date('Y-m-d H:i:s', time() + (60 * 60 * 24 * $coupon->days)),
                                'device_id' => $device->id,
                                'station_id' => $device->station_id,
                                'created_at' => date('Y-m-d H:i:s', time())
                            ];
                        }
                        CouponRecord::insert($insertRecord);
                        redis()->setex($couponCache, 60 * 10, 1);
                    } catch (\Exception $e) {
                        echo $e->getMessage();
                    }

                }
            }
        } else {
            $this->status = self::STATUS_FAILED;
            $this->save();
        }
    }


    /**自定义退款操作
     * @param $fee
     * @return string|void
     */
    public function balanceRefund($fee)
    {
        if ($this->status != 'paid') {
            return '';
        }
        $save['refund_order_no'] = 'BNR' . rand(99, 999) . $this->number;

        $refoundParams = array(
            "payment_id" => $this->payment_id,
            # 退款订单号
            "refund_order_no" => $save['refund_order_no'],
            # 退款金额
            "refund_amt" => $fee,
            "notify_url" => Common::MAIN_HOST . '/user/order/refund_balance'
        );
        $adapayService = new AdapayService();
        $adapayService->refundPayment($refoundParams);
        $save['order'] = $this->number;
        $save['fee'] = $fee;
        $save['result'] = json_encode($refoundParams);
        RefundHistory::create($save);
    }


    public function distributorSettle()
    {
        if ($this->device_id) {
            $deviceModel = Device::where('id', $this->device_id)->first();
            $firstDis = Distributors::where('id', $deviceModel->distributor_id)
                ->first();
            if ($deviceModel->child_distributor_id) {
                $childDis = Distributors::where('id', $deviceModel->child_distributor_id)
                    ->first();
                $disMoney = number_format($this->fee * $childDis->rate / 100, 2);
                $childDis->balance += $disMoney;
                $childDis->save();
                $profit['profit'] = $disMoney;
                $profit['distributor_id'] = $childDis->id;
                $profit['device_id'] = $this->device_id;
                DistributorDevice::create($profit);
                Bill::record(
                    $childDis,
                    $disMoney,
                    Bill::TYPE_ORDER_PAY,
                    $this->payment_type,
                    $this->id
                );
                if ($firstDis->rate > $childDis->rate) {
                    $firstRate = $firstDis->rate - $childDis->rate;
                    if ($firstRate > 0) {
                        $firstMoney = number_format($this->fee * $firstRate / 100, 2);
                        $firstDis->balance += $firstMoney;
                        $firstDis->save();
                        $profit['profit'] = $firstMoney;
                        $profit['distributor_id'] = $firstDis->id;
                        $profit['device_id'] = $this->device_id;
                        DistributorDevice::create($profit);
                        Bill::record(
                            $firstDis,
                            $firstMoney,
                            Bill::TYPE_ORDER_PAY,
                            $this->payment_type,
                            $this->id
                        );
                    }
                }
            } else {
                $firstMoney = number_format($this->fee * $firstDis->rate / 100, 2);
                $firstDis->balance += $firstMoney;
                $firstDis->save();
                $profit['profit'] = $firstMoney;
                $profit['distributor_id'] = $firstDis->id;
                $profit['device_id'] = $this->device_id;
                DistributorDevice::create($profit);
                Bill::record(
                    $firstDis,
                    $firstMoney,
                    Bill::TYPE_ORDER_PAY,
                    $this->payment_type,
                    $this->id
                );
            }
        }
    }

}
